#  This file is part of OpenLightingDesigner.
# 
#  OpenLightingDesigner is free software: you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation, either version 3 of the License, or
#  (at your option) any later version.
#
#  OpenLightingDesigner is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with OpenLightingDesigner.  If not, see <http://www.gnu.org/licenses/>.
#
# CommDispatcher.py
# Copyright (c) 2010 - 2011 Matthew Reid

import BaseIO
from Bases import Config
from dmx.NetlinxDMX import NetlinxDMX
from dmx.usb_pro import USBProIO
from osc.oscmanager import OSCManager
from dmx.artnet.manager import ArtnetManager
from midi import MidiIO
from interprocess.SystemData import SystemData
from interprocess.ServiceConnector import ServiceConnector

class olaLoader(type):
    ui_name = 'OLA (Open Lighting Architecture)'
    def __new__(self, *args, **kwargs):
        from dmx.OSCtoOLA import OSCtoOLAHost
        return OSCtoOLAHost(*args, **kwargs)
    
class CommDispatcher(BaseIO.BaseIO, Config):
    _confsection = 'Comm'
    io_classes = {'NetlinxDMX':NetlinxDMX, 'ola_IO':olaLoader, 
                  'Artnet':ArtnetManager, 'USBPro':USBProIO}
    def __init__(self, **kwargs):
        BaseIO.BaseIO.__init__(self, **kwargs)
        Config.__init__(self, **kwargs)
        self._MainController = None
        self.SystemData = SystemData()
        self.ServiceConnector = ServiceConnector(SystemData=self.SystemData)
        self.register_signal('io_update', 'MainController_set')
        #self.register_signal('new_ola_universe')
        self.dmx_io = {}
#        self.dmx_io = {'NetlinxDMX':NetlinxDMX(hostaddr='192.168.1.9', hostport=1998),
#                       'ola':olaIO()}
#        self.dmx_io['ola'].connect('new_universe', self.on_new_ola_universe)
        osc_kwargs = kwargs.get('osc_kwargs', {})
        osc_kwargs.update({'comm':self})
        self.osc_io = OSCManager(**osc_kwargs)
        io_keys = self.get_conf('dmx_io', [])
        for key in io_keys:
            self.build_io(key, update_conf=False)
        #self.build_io('ola_IO', osc_io=self.osc_io, update_conf)
        self._hostaddr = self.get_conf('host_address')
        self._hostiface = self.get_conf('host_interface')
        #self.artnet = ArtnetManager()
        #self.artnet.do_connect()
        self.midi_io = MidiIO(comm=self)
        
    @property
    def hostaddr(self):
        if self._hostaddr:
            return self._hostaddr
        return BaseIO.detect_usable_address()
        
    @property
    def MainController(self):
        return self._MainController
    @MainController.setter
    def MainController(self, value):
        self._MainController = value
        self.emit('MainController_set')
        
    def build_io(self, io_type, **kwargs):
        cls = self.io_classes.get(io_type)
        update_conf = kwargs.get('update_conf', True)
        if cls:
            if io_type == 'ola_IO':
                kwargs.setdefault('osc_io', self.osc_io)
            kwargs.setdefault('comm', self)
            self.dmx_io.update({io_type:cls(**kwargs)})
            self.emit('io_update', key=io_type)
        if update_conf:
            self.update_conf(dmx_io=self.dmx_io.keys())
                
    def remove_io(self, io_type, **kwargs):
        io = self.dmx_io.get(io_type)
        update_conf = kwargs.get('update_conf', True)
        if io:
            io.do_disconnect()
            io.unlink()
            del self.dmx_io[io_type]
            self.emit('io_update', key=io_type)
        if update_conf:
            self.update_conf(dmx_io=self.dmx_io.keys())
        
    def do_connect(self, **kwargs):
        self.ServiceConnector.publish()
        self.osc_io.do_connect()
        for dmx in self.dmx_io.itervalues():
            dmx.do_connect()
        self.midi_io.do_connect()
        print 'comm connected'
        self.connected = True
        
    def do_disconnect(self, **kwargs):
        #self.artnet.do_disconnect()
        self.midi_io.do_disconnect()
        for dmx in self.dmx_io.itervalues():
            dmx.do_disconnect()
        self.osc_io.do_disconnect()
        print 'comm disconnected'
        self.ServiceConnector.unpublish()
        self.connected = False
        
    def shutdown(self):
        self.midi_io.do_disconnect(blocking=True)
        for dmx in self.dmx_io.itervalues():
            if hasattr(dmx, 'shutdown'):
                dmx.shutdown(blocking=True)
            else:
                dmx.do_disconnect(blocking=True)
        self.osc_io.shutdown()
        self.ServiceConnector.unpublish(blocking=True)
        self.connected = False
    
    def on_app_exit(self, *args, **kwargs):
        print 'comm app exit'
        for dmx in self.dmx_io.itervalues():
            f = getattr(dmx, 'on_app_exit', None)
            if f:
                f()

#    def on_new_universe(self, **kwargs):
#        univ = kwargs.get('universe')
#        ola = self.dmx_io['ola']
#        olauniv = ola.universes.get(univ.ola_universe_id)
#        if olauniv is not None:
#            olauniv.Universe = univ
            
    def on_new_ola_universe(self, **kwargs):
        self.emit('new_ola_universe', **kwargs)
